<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<section>
    <h4>微任务有哪些，去实现他们</h4>
    <ol>
        <li>宏任务(task)包括：script(整体代码), setTimeout, setInterval, setImmediate(nodejs), I/O, UI rendering, xhr回调，事件回调</li>
        <li>微任务(microtask)包括： Promise.then catch finally, process.nextTick(node.js), Object.observe(被弃用), MutationObserver</li>
    </ol>
</section>
<ol>
    <li>resolve方法同步执行的话，先resolve改变状态和值，然后将值传递给then的回调方法</li>
    <li>resolve方法异步执行的话，先把then的回调方法存起来，然后resolve改变状态和值，然后将值传递给then的回调方法</li>
    <li>then方法无论如何都会返回一个promise，这个promise的状态和值，取决于上一个promise的返回</li>
    <li>then中的回调方法的参数，来源于上一个promise的返回</li>
</ol>
<script>
    function getTypeName(obj) {
        const arr = Object.getOwnPropertyNames(obj);
        for (let i = 0; i < arr.length; i++) {
            const item = arr[i];
            console.log(item, obj[item]);
        }
    }

    class MyPromise {
        static name = 'MyPromise';

        constructor(resolver) {
            this['[[PromiseState]]'] = 'pending';
            this['[[PromiseResult]]'] = undefined;
            this.onFulfilledCallbacks = [];
            this.onRejectedCallbacks = [];

            if (typeof resolver !== 'function') {
                throw new Error('Promise resolver undefined is not a function');
            }

            const reject = (val) => {
                if (this['[[PromiseState]]'] === 'pending') {
                    this['[[PromiseState]]'] = 'rejected';
                    this['[[PromiseResult]]'] = val;
                    this.onRejectedCallbacks.forEach((callback) => callback(val));
                }
            }

            const resolve = (val) => {
                if (this['[[PromiseState]]'] === 'pending') {
                    if (val instanceof MyPromise) {
                        val.then(resolve, reject);
                    } else {
                        this['[[PromiseState]]'] = 'fulfilled';
                        this['[[PromiseResult]]'] = val;
                    }
                    this.onFulfilledCallbacks.forEach((callback) => callback(val));
                }
            }

            try {
                resolver(resolve, reject);
            } catch (err) {
                reject(err);
            }
        }

        // 1. 返回Promise
        // 2. 下一个Promise需要获取到上一个Promise的返回值
        then(onFulfilled, onRejected) {
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (data) => data;
            // 如果外界不传递错误处理函数，默认一个错误处理函数，把错误传递下去
            onRejected = typeof onRejected === 'function' ? onRejected : (err) => throw err;

            const promise = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        if (this['[[PromiseState]]'] === 'fulfilled') {
                            const onFulfilledRes = onFulfilled(this['[[PromiseResult]]']);
                            if (onFulfilledRes === promise) {
                                reject(new Error('Chaining cycle detected for promise #<Promise>'));
                                return;
                            }
                            onFulfilledRes instanceof MyPromise
                                ? onFulfilledRes.then(resolve, reject)
                                : resolve(onFulfilledRes);
                        } else if (this['[[PromiseState]]'] === 'rejected') {
                            // 外界传递了错误处理函数，错误就不能继续下去，用resolve
                            const onRejectedRes = onRejected(this['[[PromiseResult]]']);
                            if (onRejectedRes === promise) {
                                reject(new Error('Chaining cycle detected for promise #<Promise>'));
                                return;
                            }
                            onRejectedRes instanceof MyPromise
                                ? onRejectedRes.then(resolve, reject)
                                : resolve(onRejectedRes);
                        } else {
                            this.onFulfilledCallbacks.push(() => {
                                // 防止传入的函数出现异常
                                try {
                                    const onFulfilledRes = onFulfilled(this['[[PromiseResult]]']);
                                    onFulfilledRes instanceof MyPromise
                                        ? onFulfilledRes.then(resolve, reject)
                                        : resolve(onFulfilledRes);
                                } catch (err) {
                                    reject(err);
                                    throw err;
                                }
                            });
                            this.onRejectedCallbacks.push(() => {
                                // 防止传入的函数出现异常
                                try {
                                    const onRejectedRes = onRejected(this['[[PromiseResult]]']);
                                    onRejectedRes instanceof MyPromise
                                        ? onRejectedRes.then(resolve, reject)
                                        : resolve(onRejectedRes);
                                } catch (err) {
                                    reject(err);
                                    throw err;
                                }
                            });
                        }
                    } catch (err) {
                        reject(err);
                    }
                }, 0)
            });
            return promise;
        }

        catch(fn) {
            return this.then(null, fn);
        }

        finally() {

        }

        // 全部成功就成功，否则失败
        static all(arr) {
            return new MyPromise((resolve, reject) => {
                try {
                    const res = [];
                    let count = 0;
                    for (let i = 0; i < arr.length; i++) {
                        arr[i].then((val) => {
                            res[i] = val;
                            count++;
                            if (count === arr.length) {
                                resolve(res);
                            }
                        }, (err) => {
                            reject(err);
                        });
                    }
                } catch (err) {
                    reject(err);
                }
            })
        }

        // 返回所有操作结果
        static allSettled(arr) {
            return new MyPromise((resolve, reject) => {
                try {
                    let res = [];
                    for (let i = 0;i < arr.length;i++) {
                        const item = arr[i];
                        item.then((val) => {
                            res[i] = {
                                status: "fulfilled",
                                value: val
                            }
                        }, (err) => {
                            res[i] = {
                                status: "rejected",
                                reason: err
                            }
                        })
                    }
                    resolve(res);
                } catch (err) {
                    reject(err);
                }
            })
        }

        // 有一个成功就成功，否则失败
        static any(arr) {
            return new MyPromise((resolve, reject) => {
                try {
                    for (let i = 0;i < arr.length;i++) {
                        arr[i].then((val) => {
                            resolve(val);
                        })
                    }
                    reject('AggregateError: All promises were rejected');
                } catch (err) {
                    reject(err);
                }
            })
        }

        // 第一个成功就成功，否则失败
        static race(arr) {
            return new MyPromise((resolve, reject) => {
                try {
                    for (let i = 0;i < arr.length;i++) {
                        arr[i].then((val) => {
                            resolve(val);
                        }, (err) => {
                            reject(err);
                        })
                    }
                } catch (err) {
                    reject(err);
                }
            })
        }

        static resolve(val) {
            if (val instanceof MyPromise) {
                return val;
            } else {
                return new MyPromise((resolve, reject) => {
                    resolve(val);
                });
            }
        }

        static reject(val) {
            return new MyPromise((resolve, reject) => {
                reject(val);
            });
        }
    }

    const promise1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(1);
        }, 1000);
    });
    const promise2 = Promise.resolve(2);
    const promise3 = Promise.reject(3);
    Promise.allSettled([promise1, promise2, promise3]).then((res) => {
        console.log(res);
    }, (err) => {
        console.log('promise fail', err);
    }).catch((err) => {
        console.log('promise catch', err);
    });

    const myPromise1 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
            reject(1);
        }, 1000);
    });
    const myPromise2 = MyPromise.resolve(2);
    const myPromise3 = MyPromise.reject(3);
    MyPromise.allSettled([myPromise1, myPromise2, myPromise3]).then((res) => {
        console.log(res);
    }, (err) => {
        console.log('myPromise fail', err);
    }).catch((err) => {
        console.log('myPromise catch', err);
    });



</script>
</body>
</html>
